#pip install pyserial
import serial
import time

read_voltage = "MEAS:VOLT?"
read_current = "MEAS:CURR?"
read_power = "MEAS:POW?"
read_version = "SYST:VERS?"
read_temperature = "gettemp 1"

# 配置串行端口
def initialize_serial(com):
    ser = serial.Serial(
        # port='COM19',  # 串行端口
        port = com,
        baudrate=115200,        # 波特率
        parity=serial.PARITY_NONE,  # 校验位:None
        stopbits=serial.STOPBITS_ONE,  # 停止位:1bit
        bytesize=serial.EIGHTBITS,  # 数据位:8bit
        timeout=1            # 读超时设置
    )
    return ser

#一次简单的通信, 根据发送的命令,返回读到的数据,适合电压、电流、功率等单次读取
def once_read(ser, message):
    try:
        ser.write(message.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {message}")
        time.sleep(0.05)
        if ser.in_waiting:
            data = ser.readline()
            return data.decode('utf-8').rstrip()
        else:
            return None
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

#输出电压设置,输入电压值,单位V
def voltage_set(ser, vol_value):
    output_voltage = f"VOLT {vol_value}"
    try:
        ser.write(output_voltage.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: VOLT {output_voltage}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#根据输入步进,调用一次提升一个步进的电压值
def voltage_up(ser, step):
    output_step = f"VOLT:STEP {step}"
    try:
        ser.write(output_step.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送:  {output_step}")
        time.sleep(0.05)
        ser.write("VOLT UP".encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: VOLT UP")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

#输出最大电流设置,输入电流值,单位A
def current_set(ser, curr_value):
    output_current = f"CURR {curr_value}"
    try:
        ser.write(output_current.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {output_current}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#根据输入步进,调用一次提升一个步进的电流值
def current_up(ser, step):
    output_step = f"CURR:STEP {step}"
    try:
        ser.write(output_step.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送:  {output_step}")
        time.sleep(0.05)
        ser.write("CURR UP".encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: CURR UP")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

# 输入最大电流值设置单位A
def current_max_input(ser, curr_value):
    input_current = f"setibat {curr_value}"
    try:
        ser.write(input_current.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {input_current}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
# 输出最大功率值设置单位W
def power_max_output(ser, power_value):
    power_max_output = f"setibat {power_value}"
    try:
        ser.write(power_max_output.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {power_max_output}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

def output_on(ser):
    try:
        ser.write("OUTP ON".encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: OUTP ON")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
def output_off(ser):
    try:
        ser.write("OUTP OFF".encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: OUTP OFF")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#按键锁定设置
def key_lock(ser, lock):
    lock_status = f"lockkey {lock}"
    try:
        ser.write(lock_status.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {lock_status}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#短路保护设置
def short_circuit_protection(ser, protection):
    short_circuit_protection = f"setSFB {protection}"
    try:
        ser.write(short_circuit_protection.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {short_circuit_protection}")
        time.sleep(0.05)
        if ser.in_waiting:
            data = ser.readline()
            return data.decode('utf-8').rstrip()
        else:
            return None
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

#设置设备名称
def set_device_name(ser, name):
    device_name = "setname " + name
    try:
        ser.write(device_name.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {device_name}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#指定预设值开始
def preset_start(ser, preset):
    preset_start = f"startPreset {preset}"
    try:
        ser.write(preset_start.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {preset_start}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#设置预设值,溢出填入预设值号,步骤,电压,电流,保持时间,循环次数(后续可优化成一个表格)
def preset_set(ser, preset,step, vol, curr,keep_time,loop):
    preset_set = f"preset {preset} {step} {vol} {curr} {keep_time}"
    try:
        ser.write(preset_set.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {preset_set}")
        time.sleep(0.05)
        ser.write(f"preset {preset} 30 {loop}".encode('ascii'))  # 要发送的ASCII字符串
        time.sleep(0.05)
        ser.write(f"save preset {preset}".encode('ascii'))  # 要发送的ASCII字符串
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

#订阅设置,读取部分没想好怎么写(最好单独开一条线程处理)
def subscribe_start(ser, loop_time):
    subscribe_start = f"getmsg {loop_time}"
    try:
        ser.write(subscribe_start.encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: {subscribe_start}")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")
#校准命令
def Automatic_calibration(ser):
    try:
        ser.write("calibus 2".encode('ascii'))  # 要发送的ASCII字符串
        print(f"[test]发送: calibus 2")
        time.sleep(0.05)
    except serial.SerialException as e:
        print(f"串行通信错误: {e}")
    except Exception as e:
        print(f"发生错误: {e}")

def Constant_current(ser,out_cur_value):
    #关闭短路保护
    short_circuit_protection(ser, 0)
    #恒电流其实是先设置最大输出电流,然后根据输出电流值调整输出电压以实现无论负载如何变动都输出指定电流
    #设置最大输出电流(避免电源狂跳)
    current_set(ser, out_cur_value+0.05)
    #获取输出电流值
    while True:
        output_on(ser)
        output_current = float(once_read(ser, read_current))
        print(f"output_current {output_current}")
        #步进调高输出电压
        if output_current < out_cur_value:
            if (out_cur_value - output_current) > 0.1:
                voltage_up(ser, 0.4)
            else:
                voltage_up(ser, 0.01)
        elif output_current > out_cur_value:
            if (output_current - out_cur_value) > 0.5:
                output_voltage = float(once_read(ser, read_voltage))  #获取当前电压值
                voltage_set(ser, output_voltage - 0.1)                #调低输出电压
            else:
                output_voltage = float(once_read(ser, read_voltage))  #获取当前电压值
                voltage_set(ser, output_voltage - 0.01)                #调低输出电压

def main():
    print("开始")
    #初始化串口
    ser = initialize_serial("COM19")
    # 检查串行端口是否已经打开
    if ser.isOpen():
        print("串行端口已打开")
        # print("开始校准")
        time.sleep(1)
        # Automatic_calibration(ser)
        voltage_set(ser, 5)
        Constant_current(ser, 1.0)
        # output_on(ser)
        # current_max_input(ser, 5)
        time.sleep(1)
    # while True:
    # #     # message = input("请输入命令：")
    # #     message = read_version
    # #     print(once_read(ser, message))
    #     voltage_set(ser, 4)
    # #     voltage_up(ser, 0.5)
    # #     current_set(ser, 0.5)
    # #     current_up(ser, 0.5)
    #     message = read_voltage
    #     print(once_read(ser, message))
    # #     message = read_current
    # #     print(once_read(ser, message))
    # #     output_on(ser)
    # #     time.sleep(2)
    # #     output_off(ser)
    # #     if message == "exit":
    # #         break
    #     time.sleep(1)

    ser.close()

if __name__ == '__main__':
    main()
